﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Threading;
using ETModel;
using NLog;

namespace ETHotfix {
    /// <summary>
    /// 服务管理
    /// </summary>
    public static class ServerManager {

        /// <summary>
        /// 初始化,所有组件使用之前
        /// </summary>
        /// <param name="userHotfixDllFilePath">用户热更库dll文件路径</param>
        /// <param name="userHotfixPdbFilePath">用户热更库pdb文件路径</param>
        public static void Init(string userHotfixDllFilePath, string userHotfixPdbFilePath) {
            if (!File.Exists(userHotfixDllFilePath)) {
                throw new Exception("用户热更库dll文件不存在![" + userHotfixDllFilePath + "]");
            }
            if (!File.Exists(userHotfixPdbFilePath)) {
                throw new Exception("用户热更库pdb文件不存在![" + userHotfixPdbFilePath + "]");
            }
            DllHelper.ETUserHotfixDllFilePath = userHotfixDllFilePath;
            DllHelper.ETUserHotfixPdbFilePath = userHotfixPdbFilePath;
            Game.EventSystem.Add(typeof(Game).Assembly);
            Game.EventSystem.Add(typeof(HotfixComponentInit).Assembly);
        }

        /// <summary>
        /// 启动指定服务消息循环
        /// </summary>
        /// <param name="userModelAssembly"></param>
        /// <param name="startConfig">当前要启动的服务配置</param>
        /// <param name="loopEndEvent">需要停止循环时,发送一个Set信号,传入时初始信号需要为false</param>
        public static void StartServerLoopByConfig<NetOuterComp>(Assembly userModelAssembly, StartConfig startConfig, AutoResetEvent loopEndEvent)
            where NetOuterComp : NetworkComponent, new() {

            // 异步方法全部会回掉到主线程
            SynchronizationContext.SetSynchronizationContext(OneThreadSynchronizationContext.Instance);

            try {
                //将基础库和热更库加入事件系统
                Game.EventSystem.Add(userModelAssembly);
                Game.EventSystem.Add(DllHelper.GetUserHotfixAssembly());

                IdGenerater.AppId = startConfig.AppId;

                LogManager.Configuration.Variables["appType"] = $"{startConfig.AppType}";
                LogManager.Configuration.Variables["appId"] = $"{startConfig.AppId}";
                LogManager.Configuration.Variables["appTypeFormat"] = $"{startConfig.AppType,-8}";
                LogManager.Configuration.Variables["appIdFormat"] = $"{startConfig.AppId:0000}";

                Log.Info($"server start........................ {startConfig.AppId} {startConfig.AppType}");

                Game.Scene.AddComponent<TimerComponent>();
                Game.Scene.AddComponent<OpcodeTypeComponent>();
                Game.Scene.AddComponent<MessageDispatcherComponent>();

                // 根据不同的AppType添加不同的组件
                OuterConfig outerConfig = startConfig.GetComponent<OuterConfig>();
                InnerConfig innerConfig = startConfig.GetComponent<InnerConfig>();
                ClientConfig clientConfig = startConfig.GetComponent<ClientConfig>();


                if (startConfig.AppType.HasFlag(AppType.Manager)) {
                    // manager server组件，用来管理其它进程使用
                    if (Game.Scene.GetComponent<AppManagerComponent>() == null) Game.Scene.AddComponent<AppManagerComponent>();
                    // 内网消息组件
                    if (Game.Scene.GetComponent<NetInnerComponent>() == null) Game.Scene.AddComponent<NetInnerComponent, string>(innerConfig.Address);
                    // 外网消息组件
                    if (Game.Scene.GetComponent<NetOuterComp>() == null) Game.Scene.AddComponent<NetOuterComp, string>(outerConfig.Address);
                }
                if (startConfig.AppType.HasFlag(AppType.Realm)) {
                    if (Game.Scene.GetComponent<MailboxDispatcherComponent>() == null) Game.Scene.AddComponent<MailboxDispatcherComponent>();
                    if (Game.Scene.GetComponent<ActorMessageDispatcherComponent>() == null) Game.Scene.AddComponent<ActorMessageDispatcherComponent>();
                    if (Game.Scene.GetComponent<NetInnerComponent>() == null) Game.Scene.AddComponent<NetInnerComponent, string>(innerConfig.Address);
                    // 外网消息组件
                    if (Game.Scene.GetComponent<NetOuterComp>() == null) Game.Scene.AddComponent<NetOuterComp, string>(outerConfig.Address);
                    if (Game.Scene.GetComponent<LocationProxyComponent>() == null) Game.Scene.AddComponent<LocationProxyComponent>();
                }
                if (startConfig.AppType.HasFlag(AppType.Gate)) {
                    //邮递员组件
                    if (Game.Scene.GetComponent<MailboxDispatcherComponent>() == null) Game.Scene.AddComponent<MailboxDispatcherComponent>();
                    //actor消息分发组件
                    if (Game.Scene.GetComponent<ActorMessageDispatcherComponent>() == null) Game.Scene.AddComponent<ActorMessageDispatcherComponent>();

                    // 内网消息组件
                    if (Game.Scene.GetComponent<NetInnerComponent>() == null) Game.Scene.AddComponent<NetInnerComponent, string>(innerConfig.Address);
                    // 外网消息组件
                    if (Game.Scene.GetComponent<NetOuterComp>() == null) Game.Scene.AddComponent<NetOuterComp, string>(outerConfig.Address);
                    if (Game.Scene.GetComponent<LocationProxyComponent>() == null) Game.Scene.AddComponent<LocationProxyComponent>();
                    // 发送普通actor消息
                    if (Game.Scene.GetComponent<ActorMessageSenderComponent>() == null) Game.Scene.AddComponent<ActorMessageSenderComponent>();
                    // 发送location actor消息
                    if (Game.Scene.GetComponent<ActorLocationSenderComponent>() == null) Game.Scene.AddComponent<ActorLocationSenderComponent>();
                    // 访问location server的组件
                    if (Game.Scene.GetComponent<LocationProxyComponent>() == null) Game.Scene.AddComponent<LocationProxyComponent>();
                }
                if (startConfig.AppType.HasFlag(AppType.Location)) {
                    // 内网消息组件
                    if (Game.Scene.GetComponent<NetInnerComponent>() == null) Game.Scene.AddComponent<NetInnerComponent, string>(innerConfig.Address);
                    // location server需要的组件
                    if (Game.Scene.GetComponent<LocationComponent>() == null) Game.Scene.AddComponent<LocationComponent>();
                }
                if (startConfig.AppType.HasFlag(AppType.Map)) {
                    if (Game.Scene.GetComponent<NetOuterComp>() == null) Game.Scene.AddComponent<NetOuterComp, string>(outerConfig.Address);
                    // 内网消息组件
                    if (Game.Scene.GetComponent<NetInnerComponent>() == null) Game.Scene.AddComponent<NetInnerComponent, string>(innerConfig.Address);
                    // 访问location server的组件
                    if (Game.Scene.GetComponent<LocationProxyComponent>() == null) Game.Scene.AddComponent<LocationProxyComponent>();
                    if (Game.Scene.GetComponent<ActorMessageSenderComponent>() == null) Game.Scene.AddComponent<ActorMessageSenderComponent>();
                    if (Game.Scene.GetComponent<ActorLocationSenderComponent>() == null) Game.Scene.AddComponent<ActorLocationSenderComponent>();
                    //邮递员组件
                    if (Game.Scene.GetComponent<MailboxDispatcherComponent>() == null) Game.Scene.AddComponent<MailboxDispatcherComponent>();
                    //actor消息分发组件
                    if (Game.Scene.GetComponent<ActorMessageDispatcherComponent>() == null) Game.Scene.AddComponent<ActorMessageDispatcherComponent>();
                }
                if (startConfig.AppType.HasFlag(AppType.MapAudience)) {
                    if (Game.Scene.GetComponent<NetOuterComp>() == null) Game.Scene.AddComponent<NetOuterComp, string>(outerConfig.Address);
                    // 内网消息组件
                    if (Game.Scene.GetComponent<NetInnerComponent>() == null) Game.Scene.AddComponent<NetInnerComponent, string>(innerConfig.Address);
                    // 访问location server的组件
                    if (Game.Scene.GetComponent<LocationProxyComponent>() == null) Game.Scene.AddComponent<LocationProxyComponent>();
                    if (Game.Scene.GetComponent<ActorMessageSenderComponent>() == null) Game.Scene.AddComponent<ActorMessageSenderComponent>();
                    if (Game.Scene.GetComponent<ActorLocationSenderComponent>() == null) Game.Scene.AddComponent<ActorLocationSenderComponent>();
                    //邮递员组件
                    if (Game.Scene.GetComponent<MailboxDispatcherComponent>() == null) Game.Scene.AddComponent<MailboxDispatcherComponent>();
                    //actor消息分发组件
                    if (Game.Scene.GetComponent<ActorMessageDispatcherComponent>() == null) Game.Scene.AddComponent<ActorMessageDispatcherComponent>();
                }
                if (startConfig.AppType.HasFlag(AppType.Benchmark)) {
                    if (Game.Scene.GetComponent<NetOuterComp>() == null) Game.Scene.AddComponent<NetOuterComp, string>(outerConfig.Address);
                    if (Game.Scene.GetComponent<BenchmarkComponent>() == null) Game.Scene.AddComponent<BenchmarkComponent, string>(clientConfig.Address);
                }
                if (startConfig.AppType.HasFlag(AppType.BenchmarkWebsocketServer)) {
                    if (Game.Scene.GetComponent<NetOuterComp>() == null) Game.Scene.AddComponent<NetOuterComp, string>(outerConfig.Address);
                }
                if (startConfig.AppType.HasFlag(AppType.BenchmarkWebsocketClient)) {
                    if (Game.Scene.GetComponent<NetOuterComp>() == null) Game.Scene.AddComponent<NetOuterComp, string>(outerConfig.Address);
                    if (Game.Scene.GetComponent<WebSocketBenchmarkComponent>() == null) Game.Scene.AddComponent<WebSocketBenchmarkComponent, string>(clientConfig.Address);
                }

                //最后加载热更层里的组件
                Game.Scene.AddComponent<HotfixComponent>();

                while (!loopEndEvent.WaitOne(1)) {
                    try {
                        OneThreadSynchronizationContext.Instance.Update();
                        Game.EventSystem.Update();
                        Game.EventSystem.LateUpdate();
                    } catch (Exception e) {
                        Log.Error(e);
                    }
                }
            } catch (Exception e) {
                Log.Error(e);
            }
        }
    }
}
